
{***********************************************************}
{                                                           }
{      Informix Data Access Components                      }
{                                                           }
{      TIfxCustomMonitor & TIfxCompositMonitor component    }
{                                                           }
{      Copyright (c) 2001-2008 Luxena Software Company      }
{      http://www.luxena.com                                }
{      e-mail: support@luxena.com                           }
{                                                           }
{***********************************************************}

unit IfxMonitor;

{$I lx.inc}

interface

uses
  SysUtils, Classes, SyncObjs, IfxConsts;


type

{ Enumerations }

  TIfxMonitorHandleMode = (hmNone, hmDesign, hmRuntime, hmBoth);

  TIfxMonitorEventType = (meInformation, meWarning, meError);


const

{ Property Default Values }

 IFX_DEFAULT_HANDLE_MODE = hmRuntime;
 IFX_DEFAULT_FILTER = [meInformation, meWarning, meError];

 
type

{ TIfxCustomMonitor }

  TIfxCustomMonitor = class;

  TIfxMonitorEventTypes = set of TIfxMonitorEventType;

  TIfxMonitorMessageProc = function (const Args: array of const): string of object;

  TIfxMonitorHandleEvent = procedure (Monitor: TIfxCustomMonitor;
    EventType: TIfxMonitorEventType; const Message: string; var Handled: Boolean) of object;
  TIfxMonitorHandleException = procedure (Monitor: TIfxCustomMonitor;
    E: Exception; var Handled: Boolean) of object;

  TIfxCustomMonitor = class(TComponent)
  private
    FSyncLock: TCriticalSection;
    FHandleMode: TIfxMonitorHandleMode;
    FFilter: TIfxMonitorEventTypes;
    FOnHandleEvent: TIfxMonitorHandleEvent;
    FOnHandleException: TIfxMonitorHandleException;
    function CanHandle(EventType: TIfxMonitorEventType): Boolean;
    procedure DoHandleEvent(EventType: TIfxMonitorEventType; const Message: string);
  protected
    procedure Loaded; override;
    procedure InternalHandleEvent(EventType: TIfxMonitorEventType;
      const Message: string); virtual; abstract;
    procedure InternalHandleException(E: Exception); virtual;
    property SyncLock: TCriticalSection read FSyncLock;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    procedure AfterConstruction; override;
    procedure BeforeDestruction; override;
    procedure HandleEvent(EventType: TIfxMonitorEventType;
      const Message: string); overload;
    procedure HandleEvent(EventType: TIfxMonitorEventType;
      const Format: string; const Args: array of const); overload;
    procedure HandleEvent(EventType: TIfxMonitorEventType;
      MessageProc: TIfxMonitorMessageProc; const Args: array of const); overload;
    procedure HandleError(const Message: string); overload;
    procedure HandleInformation(const Message: string);
    procedure HandleWarning(const Message: string);
    procedure HandleException(E: Exception);
  published
    property HandleMode: TIfxMonitorHandleMode read FHandleMode write FHandleMode default IFX_DEFAULT_HANDLE_MODE;
    property Filter: TIfxMonitorEventTypes read FFilter write FFilter default IFX_DEFAULT_FILTER;
    property OnHandleEvent: TIfxMonitorHandleEvent read FOnHandleEvent write FOnHandleEvent;
    property OnHandleException: TIfxMonitorHandleException read FOnHandleException write FOnHandleException;
  end;


{ TIfxCompositMonitor }

  TIfxCompositMonitor = class;

  TIfxMonitorCollectionItem = class(TCollectionItem)
  private
    FMonitor: TIfxCustomMonitor;
    procedure SetMonitor(Value: TIfxCustomMonitor);
  protected
    function GetDisplayName: string; override;
  public
    destructor Destroy; override;
  published
    property Monitor: TIfxCustomMonitor read FMonitor write SetMonitor;
  end;

  TIfxMonitorCollection = class(TCollection)
  private
    FMonitorManager: TIfxCompositMonitor;
    function GetItem(Index: Integer): TIfxMonitorCollectionItem;
    procedure SetItem(Index: Integer; Value: TIfxMonitorCollectionItem);
  protected
    function GetOwner: TPersistent; override;
  public
    constructor Create(MonitorManager: TIfxCompositMonitor);
    function Add: TIfxMonitorCollectionItem;
    property Items[Index: Integer]: TIfxMonitorCollectionItem read GetItem write SetItem; default;
  end;

  TIfxCompositMonitor = class(TIfxCustomMonitor)
  private
    FItems: TIfxMonitorCollection;
    procedure SetItems(Value: TIfxMonitorCollection);
  protected
    procedure Notification(AComponent: TComponent; Operation: TOperation); override;
    procedure InternalHandleEvent(EventType: TIfxMonitorEventType; const Message: string); override;
    procedure InternalHandleException(E: Exception); override;
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  published
    property Items: TIfxMonitorCollection read FItems write SetItems;
  end;


const
  EventTypeToString: array [TIfxMonitorEventType] of string =
    (SInformationEventType, SWarningEventType, SErrorEventType);


implementation

uses Ifx;


{ TIfxCustomMonitor }

constructor TIfxCustomMonitor.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FSyncLock := TCriticalSection.Create;
  FHandleMode := IFX_DEFAULT_HANDLE_MODE;
  FFilter := IFX_DEFAULT_FILTER;
end;

destructor TIfxCustomMonitor.Destroy;
begin
  FSyncLock.Free;
  inherited;
end;

procedure TIfxCustomMonitor.AfterConstruction;
begin
  inherited;
  TIDACEvents.HandleObjectCreate(Self);
end;

procedure TIfxCustomMonitor.BeforeDestruction;
begin
  TIDACEvents.HandleObjectDestroy(Self);
  inherited;
end;

function TIfxCustomMonitor.CanHandle(EventType: TIfxMonitorEventType): Boolean;
begin
  if (FHandleMode = hmNone) or not (EventType in FFilter) then
    Result := False
  else if FHandleMode = hmBoth then
    Result := True
  else if csDesigning in ComponentState then
    Result := FHandleMode = hmDesign
  else
    Result := FHandleMode = hmRuntime;
end;

procedure TIfxCustomMonitor.DoHandleEvent(EventType: TIfxMonitorEventType;
  const Message: string);
var
  Handled: Boolean;
begin
  FSyncLock.Enter;
  try
    if Assigned(FOnHandleEvent) then
    begin
      Handled := False;
      FOnHandleEvent(Self, EventType, Message, Handled);
      if Handled then Exit;
    end;
    InternalHandleEvent(EventType, Message);
  finally
    FSyncLock.Leave;
  end;
end;

procedure TIfxCustomMonitor.Loaded;
begin
  inherited;
  TIDACEvents.HandleObjectLoaded(Self);
end;

procedure TIfxCustomMonitor.InternalHandleException(E: Exception);
begin
  InternalHandleEvent(meError, E.Message);
end;

procedure TIfxCustomMonitor.HandleEvent(EventType: TIfxMonitorEventType;
  MessageProc: TIfxMonitorMessageProc; const Args: array of const);
begin
  if CanHandle(EventType) then
    DoHandleEvent(EventType, MessageProc(Args));
end;

procedure TIfxCustomMonitor.HandleEvent(EventType: TIfxMonitorEventType;
  const Message: string);
begin
  if CanHandle(EventType) then
    DoHandleEvent(EventType, Message);
end;

procedure TIfxCustomMonitor.HandleEvent(EventType: TIfxMonitorEventType;
  const Format: string; const Args: array of const);
begin
  if CanHandle(EventType) then
    DoHandleEvent(EventType, SysUtils.Format(Format, Args));
end;

procedure TIfxCustomMonitor.HandleException(E: Exception);
var
  Handled: Boolean;
begin
  if CanHandle(meError) then
    FSyncLock.Enter;
    try
      if Assigned(FOnHandleException) then
      begin
        Handled := False;
        FOnHandleException(Self, E, Handled);
        if Handled then Exit;
      end;
      InternalHandleException(E);
    finally
      FSyncLock.Leave;
    end;
end;

procedure TIfxCustomMonitor.HandleInformation(const Message: string);
begin
  HandleEvent(meInformation, Message);
end;

procedure TIfxCustomMonitor.HandleWarning(const Message: string);
begin
  HandleEvent(meWarning, Message);
end;

procedure TIfxCustomMonitor.HandleError(const Message: string);
begin
  HandleEvent(meError, Message);
end;


{ TIfxCompositMonitor }

constructor TIfxCompositMonitor.Create(AOwner: TComponent);
begin
  inherited Create(AOwner);
  FItems := TIfxMonitorCollection.Create(Self);
end;

destructor TIfxCompositMonitor.Destroy;
begin
  FItems.Free;
  inherited;
end;

procedure TIfxCompositMonitor.InternalHandleEvent(
  EventType: TIfxMonitorEventType; const Message: string);
var
  I: Integer;
begin
  for I := 0 to FItems.Count - 1 do
    with FItems[I] do
      if Monitor <> nil then Monitor.HandleEvent(EventType, Message);
end;

procedure TIfxCompositMonitor.InternalHandleException(E: Exception);
var
  I: Integer;
begin
  for I := 0 to FItems.Count - 1 do
    with FItems[I] do
      if Monitor <> nil then Monitor.HandleException(E);
end;

procedure TIfxCompositMonitor.Notification(AComponent: TComponent;
  Operation: TOperation);
var
  I: Integer;
begin
  inherited;

  if (AComponent <> Self) and (Operation = opRemove) and
    (AComponent is TIfxCustomMonitor) then
  begin
    for I := FItems.Count - 1 downto 0 do
      if FItems[I].Monitor = AComponent then FItems.Delete(I);
  end;
end;

procedure TIfxCompositMonitor.SetItems(Value: TIfxMonitorCollection);
begin
  FItems.Assign(Value);
end;


{ TIfxMonitorCollectionItem }

destructor TIfxMonitorCollectionItem.Destroy;
begin
  SetMonitor(nil);

  inherited;
end;

function TIfxMonitorCollectionItem.GetDisplayName: string;
begin
  if FMonitor = nil then
    Result := inherited GetDisplayName else
    Result := FMonitor.Name;
end;

procedure TIfxMonitorCollectionItem.SetMonitor(Value: TIfxCustomMonitor);
begin
  if Value = FMonitor then Exit;

  if Value = TIfxMonitorCollection(Collection).GetOwner then
    IDACError(SCircularMonitorLink, Value);

  if Assigned(FMonitor) then
    FMonitor.RemoveFreeNotification(TIfxCompositMonitor(TIfxMonitorCollection(Collection).GetOwner));

  FMonitor := Value;

  if Assigned(FMonitor) then
    FMonitor.FreeNotification(TIfxCompositMonitor(TIfxMonitorCollection(Collection).GetOwner));
end;


{ TIfxMonitorCollection }

constructor TIfxMonitorCollection.Create(MonitorManager: TIfxCompositMonitor);
begin
  inherited Create(TIfxMonitorCollectionItem);
  FMonitorManager := MonitorManager;
end;

function TIfxMonitorCollection.Add: TIfxMonitorCollectionItem;
begin
  Result := TIfxMonitorCollectionItem(inherited Add);
end;

function TIfxMonitorCollection.GetItem(Index: Integer): TIfxMonitorCollectionItem;
begin
  Result := TIfxMonitorCollectionItem(inherited GetItem(Index));
end;

function TIfxMonitorCollection.GetOwner: TPersistent;
begin
  Result := FMonitorManager;
end;

procedure TIfxMonitorCollection.SetItem(Index: Integer; Value: TIfxMonitorCollectionItem);
begin
  inherited SetItem(Index, Value);
end;


end.